package main

import (
	"fmt"
	"sync"
)

// byte和rune类型
// byte类型：本质上是uint8类型的别名，表示一个字节，主要用于存储二进制数据，如图片、视频、音频等
// rune类型：本质上是int32类型的别名，表示一个Unicode码点，主要用于存储字符，如汉字、字母、数字等
// byte类型占1个字节，rune类型占4个字节
// go语言中为了处理非ASCII码的字符，定义新的rune类型
// go语言中字符串是以utf-8编码存储的，一个汉字占3个字节
// byte类型的取值范围是0~255，rune类型的取值范围是-2147483648~2147483647
// byte类型可以存储ASCII码字符，rune类型可以存储所有Unicode码字符
func main() {

	s := "hello你好😡, 我爱你"
	for _, v := range s { // 从字符串中取出每一个字符
		// %c表示输出对应的字符
		// %d表示输出对应的码值
		fmt.Printf("字符：%c ；码值： %d ； 类型：%T \n", v, v, v)
	}
	fmt.Println("===================================")
	// 字符串修改
	s1 := "hello"
	// s1[0] = 'a' // 不能修改字符串中的字符
	// 将字符串转换为rune切片
	s2 := []rune(s1)
	s2[0] = 'a'
	// 将rune切片转换为字符串
	s3 := string(s2)
	fmt.Println(s3)

	s1 = "hello你好"
	fmt.Printf("%T %v \n", s1, s1)

	// 单引号和双引号的区别
	c1 := 'a' // 单引号表示字符类型，底层是int32类型
	c2 := "a" // 双引号表示字符串类型，底层是string类型
	fmt.Printf("单引号： %T %v \n", c1, c1)
	fmt.Printf("双引号：%T %v \n", c2, c2)

	// 统计汉字的数量
	stra := "hello你好"
	count := 0
	for _, v := range stra {
		if v >= 0x4e00 && v <= 0x9fff {
			count++
		}
	}
	fmt.Println("汉字的数量：", count)

	strb := "hello你好你好你好你好你好10"
	count2 := countHanziConcurrent(strb)
	fmt.Println("汉字的数量：", count2)

}

// 统计汉字的数量 - 并发版
func countHanziConcurrent(s string) int {
	var wg sync.WaitGroup // 等待组
	var mutex sync.Mutex  // 互斥锁
	count := 0
	chunkSize := len(s) / 4 // 分4部分并发处理

	for i := 0; i < len(s); i += chunkSize {
		wg.Add(1)
		go func(start, end int) {
			defer wg.Done()
			localCount := 0
			for _, r := range s[start:end] {
				if isHanzi(r) {
					localCount++
				}
			}
			mutex.Lock()
			count += localCount
			mutex.Unlock()
		}(i, min(i+chunkSize, len(s)))
	}
	wg.Wait()
	return count
}

// 判断是不是汉字
func isHanzi(r rune) bool {
	return r >= 0x4e00 && r <= 0x9fff
}
